#!/usr/bin/php
<?php
/* Copyright 2017-2025 Dan Landon
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */

/* Define our plugin name. */
if (!defined('RECYCLE_PLUGIN')) {
	define('RECYCLE_PLUGIN', 'recycle.bin');
}

/* Define our plugin name. */
if (!defined('DOCROOT')) {
	define('DOCROOT', $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
}

/* Collection of the /.Recycle.Bin files to be set for the inotify task. */
$recycleBinsFile	="/tmp/".RECYCLE_PLUGIN."/recycle_bins";
$UDrecycleBinsFile	="/tmp/".RECYCLE_PLUGIN."/ud.recycle_bins";

require_once(DOCROOT."/webGui/include/Wrappers.php");

if (isset($argv[1])) {
	$smb_file = $argv[1];
	$ud_config_file = true;
} else {
	$smb_file = "/etc/samba/smb-shares.conf";
	$ud_config_file = false;
}

if (file_exists("plugins/unassigned.devices/include/lib.php")) {
	require_once("plugins/unassigned.devices/include/lib.php");
	$UD_installed = true;
} else {
	$UD_installed = false;
}	

if (!is_file($smb_file)) {
	$smb_file = "";
}

/* If smb_file is not defined then there is nothing to configure. */
if ($smb_file) {
	/* Get the recycle bin configuration. */
	$recycle_bin_cfg	= parse_plugin_cfg(RECYCLE_PLUGIN, true);

	/* Array of recycle bin parameters. */
	$parms =  array("recycle:repository"		=> ".Recycle.Bin",
					"recycle:directory_mode"	=> "0777",
					"recycle:keeptree"			=> "Yes",
					"recycle:touch"				=> "Yes",
					"recycle:touch_mtime"		=> "No",
					"recycle:minsize"			=> 1,
					"recycle:versions"			=> "Yes",
					"recycle:exclude"			=> "",   
					"recycle:exclude_dir"		=> '".Recycle.Bin"',
					"veto files"				=> ""
	);

	/* Add recycle vfs object. */
	$vfs_objects = "recycle";
	
	/* Set the directory mode. */
	if (isset($recycle_bin_cfg['DIR_MODE']) && ($recycle_bin_cfg['DIR_MODE'])) {
		$parms['recycle:directory_mode']	= $recycle_bin_cfg['DIR_MODE'];
	}

	/* Set the excluded files. */
	$parms['recycle:exclude'] = trim($recycle_bin_cfg['EXCLUDE'] ?? "");

	/* Set the excluded directories. */
	$exclude_dirs	= explode(",", trim($recycle_bin_cfg['EXCLUDE_DIRS'] ?? ""));
	$excluded_dirs	= array();
	foreach ($exclude_dirs as $d) {
		$d	= pathinfo($d);
		$b	= null;
		if (isset($d['dirname'])) {
			$i = dirname($d['dirname']);
			if ($i != ".") {
				$d['dirname'] = $i;
			}
			$b = basename($d['dirname']);
		}

		/* See if we are adding an excluded global directory or a share directory. */
		$basename	= '"'.$d['basename'].'"';

		if ($b == ".") {
			$parms['recycle:exclude_dir'] .= ",".$basename;
		} else if (isset($excluded_dirs[$b])) {
			$excluded_dirs[$b] .= ",".$basename;
		} else {
			$excluded_dirs[$b] = $basename;
		}
	}

	/* Adjust repository with user parameters. */
	if ((isset($recycle_bin_cfg['PARAMETERS'])) && ($recycle_bin_cfg['PARAMETERS'])) {
		$parms['recycle:repository'] .= "/".$recycle_bin_cfg['PARAMETERS'];
	}

	/* Parse the samba config file. */
	$smb_config = parse_ini_file($smb_file, true, INI_SCANNER_RAW);

	/* Get the excluded shares from recycle bin configuration. */
	if ((isset($recycle_bin_cfg['EXCLUDE_SHARES'])) && ($recycle_bin_cfg['EXCLUDE_SHARES'])) {
		$excluded_shares = explode(',', $recycle_bin_cfg['EXCLUDE_SHARES']);
	} else {
		$excluded_shares = array();
	}

	/* If UD is installed, we need to exclude any samba and iso mounts. */
	if ($UD_installed) {
		/* Get the samba mounts. */
		$samba_mounts = get_samba_mounts();
		foreach (get_samba_mounts() as $name => $info) {
			$s = basename($info['target']);
			if ($info['target'] && ($info['fstype'] != "root")) {
				$excluded_shares[] .= $s;
			}
		}

		/* Get ISO File Mounts. */
		foreach (get_iso_mounts() as $name => $info) {
			$s = basename($info['target']);
			if ($info['target']) {
				$excluded_shares[] .= $s;
			}
		}
	}

	/* Get all shares from the smb configuration file. */
	$smb_shares = array_keys($smb_config);

	/* Remove excluded shares - treat excluded share as a wildcard. */
	$shares = $smb_shares;
	if (!empty($excluded_shares)) {
		foreach ($excluded_shares as $e) {
			$shares = preg_grep('~'.$e.'~i', $shares, PREG_GREP_INVERT);
		}
	}

	/* Remove recycle bin parameters from the configuration. */
	foreach ($smb_shares as $s) {
		if (isset($smb_config[$s]['vfs objects'])) {
			$smb_config[$s]['vfs objects'] = trim(str_replace(array("recycle"), "", $smb_config[$s]['vfs objects']));
			if (empty($smb_config[$s]['vfs objects'])) {
				unset($smb_config[$s]['vfs objects']);
			}
		}
		$parms_keys = array_keys($parms);
		foreach ($parms_keys as $key) {
			if (isset($smb_config[$s][$key])) {
				unset($smb_config[$s][$key]);
			}
		}
	}

	/* Set if the .RecycleBin folder is hidden in user shares. */
	if (isset($recycle_bin_cfg['HIDE_FOLDER']) && ($recycle_bin_cfg['HIDE_FOLDER'] == "yes")) {
		$parms['veto files']	= "/.Recycle.Bin";
	} else {
		unset($parms['veto files']);
	}

	$recycle_bins	= "";
	if ((! $ud_config_file) || (($ud_config_file) && ($recycle_bin_cfg['INCLUDE_UD'] == 'yes'))) {
		/* Add parameters if recycle bin is running. */
		if (is_file("/var/run/recycle.bin.pid")) {
			foreach ($shares as $s) {
				/* Check if the path is writable before adding the recycle bin. */
				if (($s != "global") && (is_writable($smb_config[$s]['path']))) {
					if (isset($smb_config[$s]['vfs objects'])) {
						$smb_config[$s]['vfs objects'] = $smb_config[$s]['vfs objects']." ".$vfs_objects;
					} else {
						$smb_config[$s]['vfs objects'] = $vfs_objects;
					}
					$smb_config[$s]['vfs objects'] = trim($smb_config[$s]['vfs objects']);
					$pd = $parms['recycle:exclude_dir'];
					if (isset($excluded_dirs[$s])) {
						$parms['recycle:exclude_dir'] .= ",".$excluded_dirs[$s];
					}
					$smb_config[$s] = array_merge($smb_config[$s], $parms);
					$parms['recycle:exclude_dir'] = $pd;

					/* Get the path to the share .Recycle.Bin for inotify. */
					$inotify_path	= $smb_config[$s]['path']."/.Recycle.Bin";
					/* Make sure the .Recycle.Bin directory is there so inotify will not complain. */ 
					if (!is_dir($inotify_path)) {
						mkdir($inotify_path, 0777, true);
					}
					$recycle_bins	.= $inotify_path."\n";
				}
			}
		}
	}

	/* Rewrite the configuration file. */
	$iniFile		= "";
	$first_line	= true;
	foreach ($smb_config as $key => $share) {
		if ($first_line) {
			$iniFile .= "[$key]";
			$first_line	= false;
		} else {
			$iniFile .= "\n[$key]";
		}
		$entryKeys = array_keys($smb_config[$key]);
		foreach ($entryKeys as $entry) {
			$iniFile .= "\n\t".$entry.' = '.$smb_config[$key][$entry];
		}

		/* If rewritting unassigned devices share add final line break. */
		if ($key == "global") {
			$iniFile	.= "\n";
		}
	}

	/* If rewritting smb-shares.conf add final line break. */
	if (! $ud_config_file) {
		$iniFile	.= "\n";
	}

	/* Write the file of inotify directories to monitor. */
	if ($recycle_bins) {
		/* Be sure the temp directory exists. */
		if (! is_dir("/tmp/".RECYCLE_PLUGIN)) {
			mkdir("/tmp/".RECYCLE_PLUGIN, 0777, true);
		}

		/* This is the output file. */
		$file	= $ud_config_file ? $UDrecycleBinsFile : $recycleBinsFile;

		/* Write the inotify list of directories to monitor. */
		file_put_contents($file, $recycle_bins, FILE_APPEND);
	}

	/* Write the new configuration. */
	if ($iniFile) {
		file_put_contents($smb_file, $iniFile);
	}
}
?>
